﻿using mozhi.smarterp.Business.Enums;
using mozhi.smarterp.Business.Interfaces;
using mozhi.smarterp.Business.Sales;
using Mozhi.Abp.Domain.BasicData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Volo.Abp;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;

namespace mozhi.smarterp.Business.Purchases
{
    /// <summary>
    /// 采购价目表
    /// </summary>
    public class PurchaseProductPrice : AuditedAggregateRoot<Guid>, IMultiTenant 
    {
        public Guid? TenantId { get; private set; }

        public Guid? SupplierId { get; private set; }

        public Supplier Supplier { get; private set; }

        public string Code {  get; private set; }

        public string Name { get; private set; }

        public Guid CurrencyId { get; private set; }

        public Currency Currency { get; private set; }

        public bool IncludeTax {  get; private set; }

        public List<PurchaseProductPriceItem> Items { get; private set; }

        private PurchaseProductPrice() { }

        public PurchaseProductPrice(Guid id, string code, string name, Supplier supplier, Currency currency, bool includeTax)
        {
            Id = id;
            Supplier = supplier;
            SupplierId = supplier?.Id;
            Code = code;
            Name = name;
            Currency = currency;
            CurrencyId = Currency == null ? default : currency.Id;
            IncludeTax = includeTax;
            Items = new List<PurchaseProductPriceItem>();

            Validate();
        }

        public void Change(string code, string name, Supplier supplier, Currency currency, bool includeTax)
        {
            Supplier = supplier;
            SupplierId = supplier?.Id;
            Code = code;
            Name = name;
            Currency = currency;
            CurrencyId = Currency == null ? default : currency.Id;
            IncludeTax = includeTax;

            Validate();
        }

        public void SetItems(List<PurchaseProductPriceItem> items)
        {
            if (items == null || items.Count == 0)
                throw new ArgumentException("items is null");

            Items = Items ?? new List<PurchaseProductPriceItem>();

            items.ForEach(x =>
            {
                AddOrUpdateItem(x);
            });

            //删除掉不存在的分录
            var itemIds = items.Select(item => item.Id).ToList();

            var deleted = Items.Where(x => !itemIds.Contains(x.Id)).ToList();

            deleted.ForEach(x => Items.Remove(x));

            //重新排序
            int index = 0;
            Items.ToList().ForEach(x => x.SetIndex(index++));
        }


        #region
        private void Validate()
        {
            if (Currency == null)
                throw new UserFriendlyException("币别不存在", "100000");

            Currency.Validate();

            if (Supplier != null)
                Supplier.Validate();

            Check.NotNullOrEmpty(Code, nameof(Code));
            Check.NotNullOrEmpty(Name, nameof(Name));
            Check.NotDefaultOrNull<Guid>(CurrencyId, nameof(CurrencyId));
        }

        private void AddOrUpdateItem(PurchaseProductPriceItem item)
        {
            if (!item.Product.Saleable)
                throw new UserFriendlyException($"产品：{item.Product.Code}-{item.Product.Name}不允许采购", "100000");

            var match = Items.FirstOrDefault(x => x.Id == item.Id);

            if (match == null)
            {
                if (Items.Exists(x => x.ProductId == item.ProductId && x.MinQuantity >= item.MinQuantity && x.MaxQuantity <= x.MaxQuantity && x.EffectiveDate >= item.EffectiveDate && x.ExpirationDate <= item.ExpirationDate))
                    throw new UserFriendlyException($"产品：{item.Product.Code}价格信息已存在", "100000");

                match = item;
                match.CalculatePrice(IncludeTax);
                Items.Add(match);
            }
            else
            {
                match.Change(item.Product, item.Price, item.MinQuantity, item.MaxQuantity, item.TaxRate, item.EffectiveDate, item.ExpirationDate);
                match.CalculatePrice(IncludeTax);
            }
               
        }
        #endregion
    }

    public class PurchaseProductPriceItem : Entity<Guid>, IMultiTenant
    {
        public Guid? TenantId { get; private set; }

        public Guid ProductId { get; private set; }

        public Product Product { get; private set; }

        public Guid BasicUnitId { get; private set; }

        public decimal? MinQuantity { get; private set; }

        public decimal? MaxQuantity { get; private set; }

        public decimal Price { get; private set; }

        public TaxRate TaxRate { get; private set; }

        public Guid? TaxRateId { get; private set; }

        public decimal? TaxRateValue { get; private set; }

        public decimal PriceIncludeTax { get; private set; }

        public decimal PriceExcludeTax { get; private set; }

        public DateTime EffectiveDate { get; private set; }

        public DateTime ExpirationDate { get; private set; }

        public int Index { get; private set; }

        private PurchaseProductPriceItem() { }

        public PurchaseProductPriceItem(Guid id, Product product, decimal price , decimal? minQuantity, decimal? maxQuantity, TaxRate taxRate , DateTime effectiveDate, DateTime expirationDate)
        {
            Id = id;
            Product = product;
            ProductId = product == null ? default : product.Id;
            BasicUnitId = product == null ? default : product.BasicUnitId;
            EffectiveDate = effectiveDate;
            ExpirationDate = expirationDate;
            Price = price;
            SetTaxRate(taxRate);
            MinQuantity = minQuantity;
            MaxQuantity = maxQuantity;

            Validate();
        }

        public void Change(Product product, decimal price, decimal? minQuantity, decimal? maxQuantity, TaxRate taxRate , DateTime effectiveDate, DateTime expirationDate)
        {
            Product = product;
            ProductId = product == null ? default : product.Id;
            BasicUnitId = product == null ? default : product.BasicUnitId;

            EffectiveDate = effectiveDate;
            ExpirationDate = expirationDate;
            Price = price;
            SetTaxRate(taxRate);

            MinQuantity = minQuantity;
            MaxQuantity = maxQuantity;

            Validate();
        }

        public void CalculatePrice(bool includeTax)
        {
            if (Price <= 0)
                throw new UserFriendlyException("单价必须大于0", "100000");

            PriceIncludeTax = TaxRate==null ? Price : TaxRate.GetIncludeTaxValue(Price, includeTax);
            PriceExcludeTax = TaxRate == null ? Price : TaxRate.GetExcludeTaxValue(Price, includeTax);
        }

        public void SetIndex(int index)
        {
            Index = index;
        }

        #region
        private void Validate()
        {
            if (Product == null)
                throw new UserFriendlyException("产品不存在", "100000");

            Product.Validate();

            if (Price <= 0)
                throw new UserFriendlyException("单价必须大于0", "100000");

            Check.NotDefaultOrNull<Guid>(ProductId, nameof(ProductId));
            Check.NotDefaultOrNull<Guid>(BasicUnitId, nameof(BasicUnitId));
        }

        private void SetTaxRate(TaxRate taxRate)
        {
            if(taxRate!=null)
                taxRate.Validate();

            TaxRate = taxRate;

            TaxRateId = taxRate?.Id;
            TaxRateValue = taxRate?.Rate;
        }
        #endregion
    }
}
